/* eslint-disable */
// @ts-nocheck
import { isObject } from '@/library/tool-kits/is-valid'

export const FUNC_ERROR_TEXT = 'Expected a Function'

/**
 * @borrows https://juejin.cn/post/6844903990639984654#heading-7
 * @description 抖动函数
 * @param {Function} func - 目标函数
 * @param {number} wait - 需要等待的毫秒数
 * @param {Options} options - 选项对象
 * @param {boolean} [options.leading=false] 指定在延迟开始前调用。
 * @param {boolean} [options.trailing=true] 指定在延迟结束后调用。
 * @param {number} [options.maxWait] `func`允许被延迟的最大值。需 `>=wait`
 * @returns 返回新的 debounced（防抖动）函数
 */
export function debounce(func, wait, options) {
  var timerId, // 定时器 ID
    lastThis, // 最后一次调用时的this值
    lastArgs, // 最后一次调用时的参数
    lastCallTime, // 最后一次调用时间
    lastInvokeTime = 0, // 最后一次实际执行时间
    maxWait, // 计算最大等待时间（>=wait）
    maxing = false, // 是否设置了最大等待时间
    leading = false, // 是否在延迟开始前立即调用
    trailing = true, // 是否在延迟结束后调用
    result, // 函数执行结果
    now = Date.now,
    nativeMax = Math.max,
    nativeMin = Math.min;

  formatArgs()

  debounced.cancel = cancel
  debounced.flush = flush
  return debounced

  function formatArgs() {
    if (typeof func != 'function') {
      throw new TypeError(FUNC_ERROR_TEXT)
    }

    wait = +wait || 0
    if (isObject(options)) {
      maxing = 'maxWait' in options
      maxWait = maxing ? nativeMax(+options.maxWait || 0, wait) : maxWait
      leading = !!options.leading
      trailing = 'trailing' in options ? !!options.trailing : trailing
    }
  }

  function startTimer(needWait) {
    return setTimeout(timeExpired, needWait)
  }

  function timeExpired() {
    var time = now(),
      canInvoke = shouldInvoke(time);

    if (canInvoke) {
      return trailingEdge(time)
    }

    var realwait = remainingWait(time)
    // 重新启动计时器
    timerId = startTimer(realwait)

    // 计算真正延迟触发的时间
    function remainingWait(time) {
      var timeSinceLastCall = time - lastCallTime,
        timeSinceLastInvoke = time - lastInvokeTime,
        timeWaiting = wait - timeSinceLastCall;
      return maxing
        ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)
        : timeWaiting
    }
  }

  function shouldInvoke(time) {
    var timeSinceLastCall = time - lastCallTime,
      timeSinceLastInvoke = time - lastInvokeTime;

    return (
      lastCallTime === undefined || // 如果是第一次调用，则一定允许
      timeSinceLastCall >= wait || // 等待时间超过设置的时间
      timeSinceLastCall < 0 || // 当前时刻早于上次事件触发时间，比如说调整了系统时间
      (maxing && timeSinceLastInvoke >= maxWait) // 等待时间超过最大等待时间
    )
  }

  function invokeFunc(time) {
    var args = lastArgs,
      thisArg = lastThis

    lastArgs = lastThis = undefined
    lastInvokeTime = time

    result = func.apply(thisArg, args)
    return result
  }

  function leadingEdge(time) {
    lastInvokeTime = time
    timerId = startTimer(wait)
    return leading ? invokeFunc(time) : result
  }

  function trailingEdge(time) {
    timerId = undefined

    if (trailing && lastArgs) {
      return invokeFunc(time)
    }

    lastArgs = lastThis = undefined
    return result
  }

  function debounced(...args) {
    var time = now(),
      isInvoking = shouldInvoke(time);
    lastArgs = arguments
    lastThis = this
    lastCallTime = time

    if (isInvoking) {
      if (timerId === undefined) {
        return leadingEdge(lastCallTime)
      }
      if (maxing) {
        clearTimeout(timerId)
        timerId = startTimer(wait)
        return invokeFunc(lastCallTime)
      }
    }
    /**
     * case：trailing 为 true
     * 前一个 wait 的 trailingEdge 已经执行了函数
     * 而这次函数被调用时 shouldInvoke 不满足条件
     * 因此要设置定时器，在本次的 trailingEdge 保证函数被执行
     * 为 throttle 服务
     */
    if (timerId === undefined) {
      timerId = startTimer(wait)
    }
    return result
  }

  // 取消 debounce 函数
  function cancel() {
    if (timerId !== undefined) {
      clearTimeout(timerId)
    }
    lastInvokeTime = 0
    lastArgs = lastCallTime = lastThis = timerId = undefined
  }

  // 取消任务并立即执行一次`debounce`函数
  function flush() {
    return timerId === undefined ? result : trailingEdge(now())
  }
}

/**
 * @description 节流函数
 * @param {Function} func - 目标函数
 * @param {number} wait - 需要等待的毫秒数
 * @param {Options} options - 选项对象
 * @param {boolean} [options.leading=true] 指定在延迟开始前调用
 * @param {boolean} [options.trailing=true] 指定在延迟结束后调用。
 */
export function throttle(func, wait, options) {
  var leading = true,
      trailing = true;

  if (typeof func !== 'function') {
    throw new TypeError(FUNC_ERROR_TEXT);
  }

  if (isObject(options)) {
    leading = 'leading' in options ? !!options.leading : leading;
    trailing = 'trailing' in options ? !!options.trailing : trailing;
  }

  return debounce(func, wait, {
    leading: leading,
    maxWait: wait,
    trailing: trailing,
  });
}
